/*
 * @Descripttion: 
 * @version: 
 * @Author: 宣某人
 * @Date: 2020-05-11 13:17:30
 * @LastEditors: 许振富(jia)
 * @LastEditTime: 2021-12-11 23:54:34
 */
#include "Bsp_Key.h"
#include "stm32f10x.h"

#define Key_1_Pin 			GPIO_Pin_7
#define Key_1_GPIO_Port 	GPIOB


#define HARD_KEY_NUM 1           /* 实体按键个数 */
#define KEY_COUNT (HARD_KEY_NUM) /* 1个独立建 */


//保存每个按键的动作信息
static KEY_T s_tBtn[KEY_COUNT] = {0};
static KEY_FIFO_T s_tKey; /* 按键FIFO变量,结构体 */

static void Key_InitVar(void);
static void Key_InitHard(void);
static void Key_Detect(unsigned char i);

static unsigned char KeyPinActive(unsigned char _id)
{    
    int ST = 0;
    switch (_id)
    {
    case 0:
		ST = GPIO_ReadInputDataBit(Key_1_GPIO_Port, Key_1_Pin);
        break;

    default:
        break;
    }
    /* p判断当前值是否达到触发阈值 */
    if (ST == 1)
    {
        return 1;
    }
    return 0;
}

static unsigned char IsKeyDownFunc(unsigned char _id)
{
    /* 实体单键 */
    if (_id < HARD_KEY_NUM)
    {
        unsigned char i;
        unsigned char count = 0;
        unsigned char save = 255;

        /* 判断有几个键按下 */
        for (i = 0; i < HARD_KEY_NUM; i++)
        {
            if (KeyPinActive(i))
            {
                count++;
                save = i;
            }
        }

        if (count == 1 && save == _id)
        {
            return 1; /* 只有1个键按下时才有效 */
        }

        return 0;
    }

    return 0;
}
/**
 * @函数名: Key_InitVar
 * @test: test?font
 * @用处: 初始化键值，FIFO归零，设置按键连发属性
 * @入口参数: 
 * @返回值: 
 */
static void Key_InitVar(void)
{
    unsigned char i;

    /* 对按键FIFO读写指针清零 */
    s_tKey.Read = 0;
    s_tKey.Write = 0;
    s_tKey.Read2 = 0;

    /* 给每个按键结构体成员变量赋一组缺省值 */
    for (i = 0; i < KEY_COUNT; i++)
    {
//        s_tBtn[i].LongTime = KEY_LONG_TIME;    /* 长按时间 0 表示不检测长按键事件 */
		s_tBtn[i].LongTime = 0;    /* 长按时间 0 表示不检测长按键事件 */
        s_tBtn[i].Count = KEY_FILTER_TIME / 2; /* 计数器设置为滤波时间的一半 */
        s_tBtn[i].State = 0;                   /* 按键缺省状态，0为未按下 */
        s_tBtn[i].RepeatSpeed = 0;             /* 按键连发的速度，0表示不支持连发 */
        s_tBtn[i].RepeatCount = 0;             /* 连发计数器 */
    }

    /* 如果需要单独更改某个按键的参数，可以在此单独重新赋值 */

    /* 支持长按1秒后，自动连发 */
    //Set_KeyParam(KID_K1, 100, 6);
    Set_KeyParam(1, 100, 6);
    Set_KeyParam(2, 100, 6);
}
/**
 * @函数名: Key_InitHard
 * @test: test?font
 * @用处: 
 * @入口参数: 
 * @返回值: 
 */
static void Key_InitHard(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;


    GPIO_InitStructure.GPIO_Pin = Key_1_Pin; 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; 
    GPIO_Init(Key_1_GPIO_Port, &GPIO_InitStructure); 
}

void Key_Init(void)
{
    Key_InitHard();
    Key_InitVar();
}
/**
 * @函数名: Key_Put
 * @test: test?font
 * @用处: 向FIFO中压入一个键值
 * @入口参数: 
 * @返回值: 
 */
void Key_Put(unsigned char _KeyCode)
{
    s_tKey.Buf[s_tKey.Write] = _KeyCode;

    if (++s_tKey.Write >= KEY_FIFO_SIZE)
    {
        s_tKey.Write = 0;
    }
}
/**
 * @函数名: Key_Get
 * @test: test?font
 * @用处: 从FIFO中读取一个键值
 * @入口参数: 
 * @返回值: 
 */
unsigned char Key_Get(void)
{
    unsigned char ret;
    /*无数据时返回*/
    if (s_tKey.Read == s_tKey.Write)
    {
        return KEY_NONE;
    }
    else
    {
        ret = s_tKey.Buf[s_tKey.Read];

        if (++s_tKey.Read >= KEY_FIFO_SIZE)
        {
            s_tKey.Read = 0;
        }
		
        switch (ret)
        {
            case KEY_1_DOWN:
            case KEY_2_DOWN:
            case KEY_3_DOWN:
//                BEEP_Start(1,1,1);
            break;
            default:
            break;
        }
        switch (ret)
        {
//        case KEY_1_DOWN:DeBug_Log("key:KEY_1_DOWN\n");break;
//        case KEY_1_UP  :DeBug_Log("key:KEY_1_UP \n");break;
//        case KEY_1_LONG:DeBug_Log("key:KEY_1_LONG\n");break;
//        case KEY_2_DOWN:DeBug_Log("key:KEY_2_DOWN\n");break;
//        case KEY_2_UP  :DeBug_Log("key:KEY_2_UP \n");break;
//        case KEY_2_LONG:DeBug_Log("key:KEY_2_LONG\n");break;
//        case KEY_3_DOWN:DeBug_Log("key:KEY_3_DOWN\n");break;
//        case KEY_3_UP  :DeBug_Log("key:KEY_3_UP \n");break;
//        case KEY_3_LONG:DeBug_Log("key:KEY_3_LONG\n");break;
//        case KEY_4_DOWN:DeBug_Log("key:KEY_4_DOWN\n");break;
//        case KEY_4_UP  :DeBug_Log("key:KEY_4_UP \n");break;
//        case KEY_4_LONG:DeBug_Log("key:KEY_4_LONG\n");break;
//        case KEY_5_DOWN:DeBug_Log("key:KEY_5_DOWN\n");break;
//        case KEY_5_UP  :DeBug_Log("key:KEY_5_UP \n");break;
//        case KEY_5_LONG:DeBug_Log("key:KEY_5_LONG\n");break;
        
        default:
            break;
        }
        return ret;
    }
}
/**
 * @函数名: Key_GetState
 * @test: test?font
 * @用处: 读取某个按键的状态
 * @入口参数: 
 * @返回值: 
 */
unsigned char Key_GetState(KEY_ID_E _ucKeyID)
{
    return s_tBtn[_ucKeyID].State;
}
/**
 * @函数名: Set_KeyParam
 * @test: test?font
 * @用处: 设置按键参数
 * @入口参数: _ucKeyID：按键名 _LongTime：长按事件标准 _RepeatSpeed：连发速度
 * @返回值: 
 */
void Set_KeyParam(unsigned char _ucKeyID, unsigned short _LongTime, unsigned char _RepeatSpeed)
{
    s_tBtn[_ucKeyID].LongTime = _LongTime;       /* 长按时间 0 表示不检测长按键事件 */
    s_tBtn[_ucKeyID].RepeatSpeed = _RepeatSpeed; /* 按键连发的速度，0表示不支持连发 */
    s_tBtn[_ucKeyID].RepeatCount = 0;            /* 连发计数器 */
}
/**
 * @函数名: Clear_Key
 * @test: test?font
 * @用处: 清空FIFO
 * @入口参数: 
 * @返回值: 
 */
void Clear_Key(void)
{
    s_tKey.Read = s_tKey.Write;
}
/**
 * @函数名: Key_Detect
 * @test: test?font
 * @用处: 检测按键的状态，需周期性调用
 * @入口参数: 按键的ID
 * @返回值: 
 */
static void Key_Detect(unsigned char i)
{
    KEY_T *pBtn;

    pBtn = &s_tBtn[i];
    //如果按键按下
    if (IsKeyDownFunc(i))
    {
        //按下时间小于KEY_FILTER_TIME则时间 = KEY_FILTER_TIME
        if (pBtn->Count < KEY_FILTER_TIME)
        {
            pBtn->Count = KEY_FILTER_TIME;
        }
        //按下时间小大KEY_FILTER_TIME小于2 * KEY_FILTER_TIME，则++，滤波
        else if (pBtn->Count < 2 * KEY_FILTER_TIME)
        {
            pBtn->Count++;
        } //按键时间到达2 * KEY_FILTER_TIME完成滤波，是有效按键
        else
        {
            //若之前未有按键按下标准则反转标志
            if (pBtn->State == 0)
            {
                pBtn->State = 1;
                /* 发送按钮按下的消息 */
                Key_Put((unsigned char)(3 * i + 1));
            }
            //若按键支持长按
            if (pBtn->LongTime > 0)
            {
                //若当前长按时间小于长按标志
                if (pBtn->LongCount < pBtn->LongTime)
                {
                    /* 到达标志后发送按钮持续按下的消息 */
                    if (++pBtn->LongCount == pBtn->LongTime)
                    {
                        /* 键值放入按键FIFO */
                        Key_Put((unsigned char)(3 * i + 3));
                    }
                }
                else
                {
                    //若支持连发，判断连发时间
                    if (pBtn->RepeatSpeed > 0)
                    {
                        //时间到达写入按下事件
                        if (++pBtn->RepeatCount >= pBtn->RepeatSpeed)
                        {
                            pBtn->RepeatCount = 0;
                            /* 常按键后，每隔xms发送1个按键 */
                            Key_Put((unsigned char)(3 * i + 1));
                        }
                    }
                }
            }
        }
    }
    else
    {
        if (pBtn->Count > KEY_FILTER_TIME)
        {
            pBtn->Count = KEY_FILTER_TIME;
        }
        else if (pBtn->Count != 0)
        {
            pBtn->Count--;
        }
        else
        {
            if (pBtn->State == 1)
            {
                pBtn->State = 0;

                /* 发送按钮弹起的消息 */
                Key_Put((unsigned char)(3 * i + 2));
            }
        }

        pBtn->LongCount = 0;
        pBtn->RepeatCount = 0;
    }
}
/**
 * @函数名: Key_Scan10ms
 * @test: test?font
 * @用处: 扫描所有按键，要10MS调用一次
 * @入口参数: 
 * @返回值: 
 */
void Key_Scan10ms(void)
{
    unsigned char i;

    for (i = 0; i < KEY_COUNT; i++)
    {
        Key_Detect(i);
    }
}
